import { _decorator, Component, director, EventKeyboard, game, Input, input, instantiate, KeyCode, Node, Prefab, RigidBody, Vec3 } from 'cc';
import { TankType } from '../Enum/TankType';
const { ccclass, property } = _decorator;

@ccclass('TankShooting')
export class TankShooting extends Component {
    @property
    public playerNumber: number = 1;     // Used to identify the different players.
    @property(Prefab)
    public shell: Prefab = null!;   // Prefab of the shell.
    @property(Node)
    public fireTransform: Node = null!;  // A child of the tank where the shells are spawned.
    @property(Node)
    public arrow: Node = null!;  // Arrow

    @property
    public minLaunchForce = 15;                    // The force given to the shell if the fire button is not held.
    @property
    public maxLaunchForce = 30;                    // The force given to the shell if the fire button is held for the max charge time.
    @property
    public maxChargeTime = 0.75;

    public shootingKey: KeyCode;
    public tankType: TankType = TankType.Player;

    private currentLaunchForce = 15;                // The force that will be given to the shell when the fire button is released.
    private chargeSpeed = 0;                       // How fast the launch force increases, based on the max charge time.
    private fired = false;                         // Whether or not the shell has been launched with this button press.
    private stamina = false;

    start() {
        this.arrow.active = false;
        if (this.tankType == TankType.Player) {
            input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
            input.on(Input.EventType.KEY_PRESSING, this.onKeyPress, this);
            input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
        }
        this.chargeSpeed = (this.maxLaunchForce - this.minLaunchForce) / this.maxChargeTime;
    }

    onDestroy() {
        if (this.tankType == TankType.Player) {
            input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
            input.off(Input.EventType.KEY_PRESSING, this.onKeyPress, this);
            input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
        }
    }

    onKeyDown(event: EventKeyboard) {
        if (event.keyCode == this.shootingKey) {
            this.fired = false;
            this.currentLaunchForce = this.minLaunchForce;
        }
    }


    onKeyPress(event: EventKeyboard) {
        if (event.keyCode == this.shootingKey && !this.fired) {
            this.stamina = true;
        }
    }

    onKeyUp(event: EventKeyboard) {
        if (event.keyCode == this.shootingKey && !this.fired) {
            this.fire();
        }
    }

    fire() {
        this.fired = true;
        this.stamina = false;
        // Instantiate the shell at the fireTransform's position and rotation
        let node = instantiate(this.shell);
        node.setParent(this.node.parent);
        let shellInstance: RigidBody = node.getComponent(RigidBody);
        shellInstance.node.setWorldPosition(this.fireTransform.worldPosition);
        shellInstance.node.setWorldRotation(this.fireTransform.worldRotation);

        // Set the shell's velocity to the launch force in tssshe fireTransform's forward direction
        let forwardDir = Vec3.transformQuat(new Vec3(), Vec3.UNIT_Z, this.fireTransform.worldRotation);
        Vec3.normalize(forwardDir, forwardDir);
        const velocity = new Vec3(forwardDir.x * this.currentLaunchForce,
            forwardDir.y * this.currentLaunchForce,
            forwardDir.z * this.currentLaunchForce);
        shellInstance.setLinearVelocity(velocity);

        // 计算并打印落点
        const impactPos = this.calculateGroundImpact();
        if (impactPos) {
            console.log("子弹落点坐标:", impactPos);
        }
    }


    public calculateGroundImpact(
        gravity: Vec3 = new Vec3(0, -10, 0),
        linearDamping: number = 0.1
    ): Vec3 | null {
        // 考虑线性阻尼的速度衰减公式: v(t) = v0 * e^(-linearDamping * t)
        // 需要数值积分计算位置，因为阻尼导致运动方程非线性
        const dt = 0.01; // 时间步长（越小越精确）
        let t = 0;
        let forwardDir = Vec3.transformQuat(new Vec3(), Vec3.UNIT_Z, this.fireTransform.worldRotation);
        Vec3.normalize(forwardDir, forwardDir);
        let pos = this.fireTransform.worldPosition.clone();
        let vel =  new Vec3(forwardDir.x * this.currentLaunchForce,
            forwardDir.y * this.currentLaunchForce,
            forwardDir.z * this.currentLaunchForce).clone();
        while (pos.y > 0) {
            // 更新速度（考虑阻尼）
            vel.x *= Math.exp(-linearDamping * dt);
            vel.y *= Math.exp(-linearDamping * dt);
            vel.z *= Math.exp(-linearDamping * dt);
            // 更新位置（考虑重力）
            pos.x += vel.x * dt;
            pos.y += vel.y * dt + 0.5 * gravity.y * dt * dt;
            pos.z += vel.z * dt;
            // 更新速度（重力影响）
            vel.y += gravity.y * dt;
            t += dt;
            // 防止无限循环（例如阻尼过大导致子弹几乎不动）
            if (t > 100) {
                return null;
            }
        }
        // 确保子弹最终在地面或以下
        if (pos.y <= 0) {
            return new Vec3(pos.x, 0, pos.z);
        }
        return null;
    }

    update(deltaTime: number) {
        this.arrow.active = this.stamina;
        if (this.currentLaunchForce >= this.maxLaunchForce && !this.fired) {
            this.currentLaunchForce = this.maxLaunchForce;
            this.fire();
        }
        if (!this.fired && this.stamina) {
            this.currentLaunchForce += this.chargeSpeed * deltaTime;

        }
    }

    public bindKey(sKey: KeyCode) {
        this.shootingKey = sKey;
    }
}

